/**
 * Java program for classifying short text messages into two classes.
 */
package classifier;
import weka.core.Attribute;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.FastVector;
import weka.core.Utils;
import weka.core.converters.TextDirectoryLoader;
import weka.core.stemmers.SnowballStemmer;
import weka.classifiers.Classifier;
import weka.classifiers.Classifier.*;
// import weka.classifiers.bayes.NaiveBayes;
// import weka.classifiers.lazy.IBk;
// import weka.classifiers.trees.J48;
// import weka.datagenerators.classifiers.classification.BayesNet;
import weka.classifiers.functions.SMO;
import weka.filters.Filter;
import weka.filters.unsupervised.attribute.StringToWordVector;
import java.io.*;
import java.util.Arrays;

public class NewsClassifier implements Serializable {

  /* The training data gathered so far. */
  private Instances m_Data = null;

  /* The filter used to generate the word counts. */
  private StringToWordVector m_Filter = new StringToWordVector();

  /* The actual classifier. */
  // private Classifier m_Classifier = new IBk();
  private Classifier m_Classifier = new SMO();

  /* Whether the model is up to date. */
  private boolean m_UpToDate;

  /**
   * Constructs empty training dataset.
   */
	public NewsClassifier() throws Exception {
		setFilterSettings(); 
		TextDirectoryLoader loader = new TextDirectoryLoader();
		loader.setCharSet("UTF-8");
		loader.setDirectory(new File("data"));
		Instances dataRaw = loader.getDataSet();
		m_Data = dataRaw;
		m_Filter.setInputFormat(m_Data);
		Instances filteredData  = Filter.useFilter(m_Data, m_Filter);
		m_Classifier.buildClassifier(filteredData);
		m_UpToDate = true;
	}
  
  /*
   * Seteo de los filtros para las instancias
   */
  private void setFilterSettings(){
	  m_Filter.setIDFTransform(true);
	  m_Filter.setTFTransform(true);
	  m_Filter.setUseStoplist(true);
	  m_Filter.setLowerCaseTokens(true);
	  m_Filter.setStopwords(new File("spanishSW.txt"));
	  m_Filter.setStemmer(new SnowballStemmer("spanish"));
	  m_Filter.setMinTermFreq(10);
	  m_Filter.setWordsToKeep(10000);
  }

  /**
   * Updates model using the given training message.
   */
  /*public void updateData(String message, String classValue) throws Exception {

    // Make message into instance.
    Instance instance = makeInstance(message, m_Data);

    // Set class value for instance.
    instance.setClassValue(classValue);

    // Add instance to training data.
    m_Data.add(instance);
    m_UpToDate = false;
  }*/

  /**
   * Classifies a given message.
   */
  public String classify(String message) throws Exception {

    // Check whether classifier has been built.
    if (m_Data.numInstances() == 0) {
      throw new Exception("No classifier available.");
    }
	/*
    // Check whether classifier and filter are up to date.
    if (!m_UpToDate) {

      // Initialize filter and tell it about the input format.
      m_Filter.setInputFormat(m_Data);

      // Generate word counts from the training data.
      Instances filteredData  = Filter.useFilter(m_Data, m_Filter);

      // Rebuild classifier.
      m_Classifier.buildClassifier(filteredData);
      m_UpToDate = true;
    }*/

    // Make separate little test set so that message
    // does not get added to string attribute in m_Data.
    Instances testset = m_Data.stringFreeStructure();

    // Make message into test instance.
    Instance instance = makeInstance(message, testset);

    // Filter instance.
    m_Filter.input(instance);
    Instance filteredInstance = m_Filter.output();

    // Get index of predicted class value.
    double predicted = m_Classifier.classifyInstance(filteredInstance);
    //System.out.println("VALOR: " + predicted);
    // Output class value.
    //System.err.println("Message classified as : " + m_Data.classAttribute().value((int)predicted));
	
	// System.out.println(m_Classifier.distributionForInstance(filteredInstance));
	System.out.println(Arrays.toString(m_Classifier.distributionForInstance(filteredInstance)));
	return m_Data.classAttribute().value((int)predicted);
  }

  /**
   * Method that converts a text message into an instance.
   */
  private Instance makeInstance(String text, Instances data) {

    // Create instance of length two.
    Instance instance = new Instance(2);
    //System.out.println("Antes");
    // Set value for message attribute
    Attribute messageAtt = data.attribute("text");    
    instance.setValue(messageAtt, messageAtt.addStringValue(text));
    
    // Give instance access to attribute information from the dataset.
    instance.setDataset(data);
    
    return instance;
    
  }
  
  public static NewsClassifier createFromModel(String modelName) throws Exception{
   NewsClassifier nc=null;
      try {
    	  ObjectInputStream modelInObjectFile = new ObjectInputStream(new FileInputStream(modelName));
    	  nc = (NewsClassifier) modelInObjectFile.readObject();
    	  modelInObjectFile.close();
      }
      catch (FileNotFoundException e) {
    	  System.out.println("Creando Clasificador");
    	  nc = new NewsClassifier();
		  ObjectOutputStream modelOutObjectFile = new ObjectOutputStream(new FileOutputStream(modelName));
		  modelOutObjectFile.writeObject(nc);
		  modelOutObjectFile.close();
      }
	  
	  return nc;
  }
  

  /**
   * Main method.
   */
  /*public static void main(String[] options) {

    try {

      // Read message file into string.
      String messageName = Utils.getOption('m', options);
      System.out.println(messageName);
      if (messageName.length() == 0) {
        throw new Exception("Must provide name of message file.");
      }
      FileReader m = new FileReader(messageName);
      StringBuffer message = new StringBuffer(); int l;
      while ((l = m.read()) != -1) {
    	  message.append((char)l);
      }
      m.close();
      
      // Check if class value is given.
      String classValue = Utils.getOption('c', options);
      
      // If model file exists, read it, otherwise create new one.
      String modelName = Utils.getOption('t', options);
      if (modelName.length() == 0) {
    	  throw new Exception("Must provide name of model file.");
      }
      NewsClassifier messageCl;
      try {
    	  ObjectInputStream modelInObjectFile = new ObjectInputStream(new FileInputStream(modelName));
    	  messageCl = (NewsClassifier) modelInObjectFile.readObject();
    	  modelInObjectFile.close();
      } 
      catch (FileNotFoundException e) {
    	  System.out.println("Creando Clasificador");
    	  messageCl = new NewsClassifier();
      }
      
      // Check if there are any options left
      Utils.checkForRemainingOptions(options);           
      // Process message.
      if (classValue.length() != 0) {
        messageCl.updateData(message.toString(), classValue);
      } 
      else {
    	  messageCl.classifyMessage(message.toString());
      }
      
      // Save message classifier object.
      ObjectOutputStream modelOutObjectFile = new ObjectOutputStream(new FileOutputStream(modelName));
      modelOutObjectFile.writeObject(messageCl);
      modelOutObjectFile.close();
    } 
    catch (Exception e) {
      e.printStackTrace();
    }
  }*/
}
